//
//  PSCalculator.m
//  PrefCore
//
//  Created by Sergey on 2/27/14.
//  Copyright (c) 2014 Play-on-smart. All rights reserved.
//

#import "PSCalculator.h"
#import "PSLeningradCalculator.h"
#import "PSRostovCalculator.h"
#import "PSSochiCalculator.h"

@interface PSCalculator () {
    PSPassingScorer *_passingScorer;
    PSScoreValue _costsPlaySuccess[PS_BID_MAX-PS_BID_MIN+1];
    PSScoreValue _costsPlayFail[PS_BID_MAX-PS_BID_MIN+1];
    PSScoreValue _costsWhistSuccess[PS_BID_MAX-PS_BID_MIN+1];
    PSScoreValue _costsWhistFail[PS_BID_MAX-PS_BID_MIN+1];
}

@end

@implementation PSCalculator

-(instancetype)initWithPassingScorer:(PSPassingScorer*)passingScorer
          costsPlaySuccess:(NSArray*)costsPlaySuccess
             costsPlayFail:(NSArray*)costsPlayFail
         costsWhistSuccess:(NSArray*)costsWhistSuccess
            costsWhistFail:(NSArray*)costsWhistFail
       normalizationFactor:(uint32_t)normalizationFactor {
    if (self = [super init]) {
        _passingScorer = passingScorer;
        _normalizationFactor = normalizationFactor;
        for (int i = 0 ; i != PS_BID_MAX-PS_BID_MIN+1 ; i++) {
            _costsPlaySuccess[i] = [costsPlaySuccess[i] intValue];
            _costsPlayFail[i] = [costsPlayFail[i] intValue];
            _costsWhistSuccess[i] = [costsWhistSuccess[i] intValue];
            _costsWhistFail[i] = [costsWhistFail[i] intValue];
        }
    }
    return self;
}

+(instancetype)calculatorForGameFlavor:(PSGameFlavor)flavor {
    static PSCalculator *calcs[3];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        calcs[kGameFlavorLeningrad] = [[PSLeningradCalculator alloc] init];
        calcs[kGameFlavorRostov] = [[PSRostovCalculator alloc] init];
        calcs[kGameFlavorSochi] = [[PSSochiCalculator alloc] init];
    });
    NSAssert(flavor >= 0 && flavor < 3, @"Game flavor setting is out of range.");
    return calcs[flavor];
}

-(BOOL)isClosed:(PSPlayer*)p game:(PSGame*)game settings:(PSGameSettings*)settings {
    return [game scoreForPlayerId:p.identifier].pool.current == settings.poolSize;
}

-(BOOL)isGameOver:(PSGame*)game settings:(PSGameSettings*)settings {
    for (PSPlayer *p in game.players) {
        if (![self isClosed:p game:game settings:settings]) {
            return NO;
        }
    }
    return YES;
}

-(void)writeToMountainOfPlayer:(PSPlayer*)player
                          game:(PSGame*)game
                         value:(PSScoreValue)value {
    [[game scoreForPlayerId:player.identifier].mountain addValue:value];
}

-(void)writeToPoolOfPlayer:(PSPlayer*)player
                      game:(PSGame*)game
                  settings:(PSGameSettings*)settings
                     value:(PSScoreValue)value {
    [[game scoreForPlayerId:player.identifier].pool addValue:value];
}

-(void)writeWhistsFromPlayer:(PSPlayer*)fromPlayer
                    toPlayer:(PSPlayer*)toPlayer
                        game:(PSGame*)game
                       value:(PSScoreValue)value {
    [[game scoreForPlayerId:fromPlayer.identifier].whists[toPlayer.identifier] addValue:value];
}

-(PSScoreValue) playCostSuccessWithTricks:(PSTrickCount)numTricks {
    return _costsPlaySuccess[PSGetContractIndex(numTricks)];
}

-(PSScoreValue) playCostFailureWithTricks:(PSTrickCount)numTricks {
    return _costsPlayFail[PSGetContractIndex(numTricks)];
}

-(PSScoreValue) whistCostSuccessWithTricks:(PSTrickCount)numTricks {
    return _costsWhistSuccess[PSGetContractIndex(numTricks)];
}

-(PSScoreValue) whistCostFailureWithTricks:(PSTrickCount)numTricks {
    return _costsWhistFail[PSGetContractIndex(numTricks)];
}

-(PSScoreValue) missedTrickCostWithTricks:(PSTrickCount)numTricks {
    return _costsWhistSuccess[PSGetContractIndex(numTricks)];
}

// Get the number of expected whists for open game type.
+(PSTrickCount)expectedOpenWhistsForContract:(PSTrickCount)contractTricks {
    static PSTrickCount expected[] = {4, 2, 1, 1, 1};
    return expected[PSGetContractIndex(contractTricks)];
}

// Get the number of expected whists for blind game type.
+(PSTrickCount)expectedStandingWhistsForContract:(PSTrickCount)contractTricks {
    static PSTrickCount expected[] = {2, 1, 1, 1, 1};
    return expected[PSGetContractIndex(contractTricks)];
}

-(void)passingWithGame:(PSGame*)game settings:(PSGameSettings*)settings {
    return [_passingScorer scoreGame:game withSettings:settings andCalculator:self];
}

-(void)misereWithGame:(PSGame*)game settings:(PSGameSettings*)settings {
    [[PSScorer misereScorer] scoreGame:game withSettings:settings andCalculator:self];
}

-(void)trickingWithGame:(PSGame*)game settings:(PSGameSettings*)settings {
    [[PSScorer trickingScorer] scoreGame:game withSettings:settings andCalculator:self];
}

-(void)trickingTwoPassesWithGame:(PSGame*)game settings:(PSGameSettings*)settings {
    [[PSScorer trickingTwoPassesScorer] scoreGame:game withSettings:settings andCalculator:self];
}

-(void)trickingHalfWhistWithGame:(PSGame*)game settings:(PSGameSettings*)settings {
    [[PSScorer trickingHalfWhistScorer] scoreGame:game withSettings:settings andCalculator:self];
}

-(void)trickingWithoutThreeWithGame:(PSGame*)game settings:(PSGameSettings*)settings {
    [[PSScorer trickingWithoutThreeScorer] scoreGame:game withSettings:settings andCalculator:self];
}

-(void)trickingTenWithGame:(PSGame*)game settings:(PSGameSettings*)settings {
    [[PSScorer trickingTenScorer] scoreGame:game withSettings:settings andCalculator:self];
}

@end
